/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package genomemap.data;

import genomemap.tagging.LinkingCloneStrategy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

/**
 *
 * @author stewari1
 */
public class PhysicalMapService {

    public static Clone[] getMinimalPathClones(int ch_id, int[] i,
            LinkingCloneStrategy linkingCloneStrategy) {

        return getMinimalPathClones(ch_id, i, linkingCloneStrategy,
                                    new HashMap<Integer, Boolean>());
    }

    /**
     * modifies <code>gapStatus</code> to contain the corresponding gap status.
     * the caller is assumed to create a new empty list
     * @param ch_id
     * @param probeOrder
     * @param linkCloneStrategy
     * @param gapStatus length same as clones minus 1. at index i it means if clone[i]
     * is connected with clone[i + 1]
     * @return
     */
    public static Clone[] getMinimalPathClones(int ch_id, int[] probeOrder,
            LinkingCloneStrategy linkCloneStrategy, Map<Integer, Boolean> gapStatus) {

        return buildMapClones(ch_id, probeOrder, linkCloneStrategy, false,
                              gapStatus).toArray(new Clone[0]);
    }

    public static Clone[] getFullPathClones(int ch_id, int[] probeOrder,
            Map<Integer, Boolean> gapStatus) {
        return buildMapClones(ch_id, probeOrder, null, true, gapStatus).toArray(new Clone[0]);
    }

    /**
     *
     * @param ch_id
     * @param probeOrder
     * @param linkCloneStrategy
     * @param fullMap true means full map (all linking clones)
     * false means (compressed map : single linking clone)
     * @param gapStatus description
     * @return
     */
    private static List<Clone> buildMapClones(int ch_id, int[] probeOrder,
            LinkingCloneStrategy linkCloneStrategy, boolean fullMap,
            Map<Integer, Boolean> gapStatus) {

        List<Clone> linkedCloneList = new ArrayList<>();
        PDataSource pData           = DataSource.getPDataSource(ch_id);

        pData.setOrder(probeOrder);

        int[][] binaryProfile = pData.getHybridData();
        Clone[] clones        = (Clone[]) new TreeSet(pData.getCloneSet()).toArray(new Clone[0]);
        Probe[] probes        =
            (Probe[]) new TreeSet(pData.getFullProbeSet()).toArray(new Probe[0]);

        for (int rowIndex = 0; rowIndex < probeOrder.length - 1; rowIndex++) {

            int cloneIndex = PhysicalMapServiceHelper.getCorrespondingCloneIndex(clones,
                                 probes[probeOrder[rowIndex] - 1]);

            if (cloneIndex == -1) {
                continue;
            }

            clones[cloneIndex].setProbe(true);
            linkedCloneList.add(clones[cloneIndex]);

            if (!fullMap) {

                Clone linkedClone = PhysicalMapServiceHelper.getLinkingClone(probeOrder[rowIndex]
                                        - 1, probeOrder[rowIndex + 1] - 1, binaryProfile, clones,
                                             linkCloneStrategy, linkedCloneList);

                if (linkedClone != null) {
                    linkedCloneList.add(linkedClone);
                } else {

                    gapStatus.put(new Integer(clones[cloneIndex].getOrder()),
                                  Boolean.valueOf(true));
                }

            } else {

                List<Clone> linkedClones =
                    PhysicalMapServiceHelper.getLinkingClones(probeOrder[rowIndex] - 1,
                        probeOrder[rowIndex + 1] - 1, binaryProfile, clones, linkedCloneList);

                if (linkedClones.size() != 0) {
                    linkedCloneList.addAll(linkedClones);
                } else {

                    gapStatus.put(new Integer(clones[cloneIndex].getOrder()),
                                  Boolean.valueOf(true));
                }
            }
        }

        return linkedCloneList;
    }
}
